package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.constants.RedisConstants;
import com.tianji.learning.domain.po.PointsRecord;
import com.tianji.learning.domain.vo.PointsStatisticsVO;
import com.tianji.learning.enums.PointsRecordType;
import com.tianji.learning.mapper.PointsRecordMapper;
import com.tianji.learning.service.IPointsRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 学习积分记录，每个月底清零 服务实现类
 * </p>
 *
 * @author 虎哥
 * @since 2025-03-16
 */
@Service
@RequiredArgsConstructor
public class PointsRecordServiceImpl extends ServiceImpl<PointsRecordMapper, PointsRecord> implements IPointsRecordService {

    private final StringRedisTemplate redisTemplate;

    @Override
    public void addPointsRecord(Long userId, int points, PointsRecordType type) {
        int maxPoints = type.getMaxPoints();
        LocalDateTime now = LocalDateTime.now();
        //1.判断当前方式有没有积分上限
        int realPoints = points;
        if (maxPoints > 0) {
            //2.有，则需要判断积分是否超出上限
            LocalDateTime begin = DateUtils.getDayStartTime(now);
            LocalDateTime end = DateUtils.getDayEndTime(now);
            //2.1查出今日已得积分
            int currentPoints= queryUserPointsByTypeAndDate(userId, type, begin, end);
            //2.2判断积分是否超出上限
            if (currentPoints > maxPoints) {
            //2.3积分上限，则不记录积分，结束
                return;
            }
            //2.4积分未超出上限，则记录积分
            if (currentPoints + points > maxPoints){
                realPoints = maxPoints - currentPoints;
            }
        }
        //3.没有积分上限，则直接记录积分
        PointsRecord record = new PointsRecord();
        record.setUserId(userId);
        record.setPoints(realPoints);
        record.setType(type);
        save(record);

        //4.累计积分数据到Redis的SortSet中
        String key = RedisConstants.POINTS_BOARD_KEY_PREFIX + now.format(DateUtils.POINTS_BOARD_SUFFIX_FORMATTER);
        redisTemplate.opsForZSet().incrementScore(key,userId.toString(),realPoints);
    }

    private int queryUserPointsByTypeAndDate(
            Long userId, PointsRecordType type, LocalDateTime begin, LocalDateTime end) {
        //1.查询条件
        QueryWrapper<PointsRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(PointsRecord::getUserId, userId)
                .eq(type!= null,PointsRecord::getType, type)
                .between(begin!= null && end != null,PointsRecord::getCreateTime, begin, end);

        //2.调用mapper，查询结果
        Integer points = getBaseMapper().queryUserPointsByTypeAndDate(queryWrapper);
        return points == null ? 0 : points;
    }

    @Override
    public List<PointsStatisticsVO> queryTodayPoints() {
        //1.获取用户、
        Long userId = UserContext.getUser();
        //2.获取日期
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime begin = DateUtils.getDayStartTime(now);
        LocalDateTime end = DateUtils.getDayEndTime(now);
        //3.构造查询条件
        QueryWrapper<PointsRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(PointsRecord::getUserId, userId)
                .between(PointsRecord::getCreateTime, begin, end);
        //4.调用mapper查询
        List<PointsRecord> list = getBaseMapper().queryUserPointsByDate(queryWrapper);

        //5.返回结果
        List<PointsStatisticsVO> vos = new ArrayList<>(list.size());
        for (PointsRecord record : list) {
            PointsStatisticsVO vo = new PointsStatisticsVO();
            vo.setType(record.getType().getDesc());
            vo.setMaxPoints(record.getType().getMaxPoints());
            vo.setPoints(record.getPoints());
            vos.add(vo);
        }
        return vos;
    }
}
